package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql" //	匿名导入包（在包路径前添加下画线“_”），只导入包但是不使用包内的类型和数据
)

/*
Go使用Mysql介绍之事务
 	1) 原子性
    2) 一致性
    3) 隔离性
    4) 持久性

 MySQL事务应用：
	1)  Db.Begin()        开始事务
    2)  Db.Commit()       提交事务
    3)  Db.Rollback()     回滚事务
*/

/*
定义数据库连接信息
*/
type DBConn struct {
	Dsn string // 数据库驱动连接字符串
	Db  *sql.DB
}

func main() {

	var err error
	dbConn := DBConn{
		Dsn: "root:qinxh123456@tcp(122.51.88.186:3306)/golang_db?charset=utf8",
	}
	dbConn.Db, err = sql.Open("mysql", dbConn.Dsn)
	if err != nil {
		fmt.Println(err.Error())
		panic(any(err))
		return
	} else {
		fmt.Println("连接成功！")
	}
	// 延迟关闭db
	defer func(Db *sql.DB) {
		err := Db.Close()
		if err != nil {

		}
	}(dbConn.Db)

	// 开启事务
	begin, err := dbConn.Db.Begin()
	if err != nil {
		fmt.Println("begin failed :", err)
		return
	}

	// 删除操作
	result, err := begin.Exec("delete from user where name = ?", "steven")
	if err != nil {
		fmt.Println("error：", err.Error())
		_ = begin.Rollback() // 回滚事务
		return
	} else {
		if affected, err := result.RowsAffected(); err == nil {
			fmt.Println("影响的行数：", affected)
		}
	}
	// 新增操作
	exec, err := begin.Exec("insert into user (name, password, phone) values (?, ?, ?)",
		"steven", "1234345", 13423456789)
	var thisId interface{}
	if err != nil {
		fmt.Println("error：", err.Error())
		_ = begin.Rollback() // 回滚事务
		return
	} else {
		if affected, err := exec.RowsAffected(); err == nil {
			fmt.Println("影响的行数：", affected)
		}

		if id, err := exec.LastInsertId(); err == nil {
			fmt.Println("最后插入的ID：", id)
			thisId = id
		}
	}

	// 新增操作2
	exec, err = begin.Exec("insert into user (name, password, phone) values (?, ?, ?)",
		"steven4324543", "1234345545443", 13423456789)
	if err != nil {
		fmt.Println("error：", err.Error())
		_ = begin.Rollback() // 回滚事务
		return
	} else {
		if affected, err := exec.RowsAffected(); err == nil {
			fmt.Println("影响的行数：", affected)
		}

		if id, err := exec.LastInsertId(); err == nil {
			fmt.Println("最后插入的ID：", id)
			thisId = id
		}
	}

	// 更新操作（TIPS：这里将报错，但是前面新增操作回滚了）
	r, err := begin.Exec("update userw set password = ? where id = ?", "更新后密码", thisId)
	if err != nil {
		fmt.Println("error：", err.Error())
		_ = begin.Rollback() // 回滚事务
		return
	} else {
		if affected, err := r.RowsAffected(); err == nil {
			fmt.Println("影响的行数：", affected)
		}
	}

	_ = begin.Commit() // 提交事务

}
